/*
 * @Author: shiguo
 * @Date: 2022-05-17 15:22:06
 * @LastEditors: shiguo
 * @LastEditTime: 2023-09-27 15:17:15
 * @FilePath: /@aks-dev/easyui/lib/AnimationModal/AnimationModal.tsx
 */

import * as React from "react";
import { View, Animated, Easing, LayoutRectangle, PanResponder, StyleSheet, useWindowDimensions, BackHandler, MeasureOnSuccessCallback } from 'react-native';
import type { AnimationModalProps } from '.';
import * as utils from '../../utils/lazy';
// type State = {
//     display: 'flex' | 'none';
// }
// type StateReducerProps = (state: State, action: Partial<State>) => State




export const AnimationModal: React.ForwardRefExoticComponent<
    React.PropsWithoutRef<AnimationModalProps>
    & React.RefAttributes<AnimationModalProps.RefAttributes>
>
    = React.forwardRef((props, ref) => {
        const {
            animationType = 'from-bottom',
            mask = false
        } = props || {}

        const { height } = useWindowDimensions()

        // const [state, dispatch] = React.useReducer<StateReducerProps>(
        //     (state, action) => ({ ...state, ...action }),
        //     {
        //         display: 'none'
        //     })

        const [display, setDisplay] = useCallbackState<'flex' | 'none'>('none')

        const animatedValue = React.useRef(new Animated.Value(0)).current;
        const timing = (value: number) => {
            Animated.timing(animatedValue, {
                toValue: value,
                duration: 350,
                useNativeDriver: true,
                easing: Easing.ease,
            }).start(({ finished }) => {
                /* 动画完成的回调函数 */
            });
        };


        const viewRef = React.useRef<{ measure: (callback: MeasureOnSuccessCallback) => void }>() as any
        const layoutRef = React.useRef<{
            /**：父容器的高度 */
            h0: number;
            /**：子容器的高度 */
            h1: number;
        }>({ h0: 0, h1: 0 })
        const getLayoutPromise = () => {
            return new Promise((resovle, reject) => {
                viewRef.current?.measure((...args: any[]) => {
                    if (args.length == 6) {
                        layoutRef.current.h1 = args[3]
                    }
                    resovle(args)
                })
            })
        }



        const init = React.useCallback(() => ({ show, hide, setData, getData }), [])
        React.useImperativeHandle<unknown, AnimationModalProps.RefAttributes>(ref, init, [])
        const dataRef = React.useRef<any>()
        const setData = (data?: any) => {
            dataRef.current = data
            return init()
        }

        const getData = () => dataRef.current


        const show = () => {
            setDisplay('flex', async () => {
                await utils.sleep(50)
                await getLayoutPromise()
                timing(-layoutRef.current?.h1)
            })

            return init()
        }
        const hide = () => {
            timing(0)
            setTimeout(() => {
                setDisplay('none')
            }, 300)

            return init()
        }


        React.useEffect(() => {
            let addEventListener = BackHandler.addEventListener("hardwareBackPress", () => {
                return display == 'flex'
            })
            return () => {
                addEventListener.remove()
            }
        }, [display])



        return (
            <View
                style={Object.assign({
                    display: display
                }, styles.container, props.style)}
                {...PanResponder.create({
                    onStartShouldSetPanResponder: (e, gestureState) => {
                        let pageY = e.nativeEvent.pageY
                        let topY = height - layoutRef.current.h1
                        if (pageY <= topY && !mask) {
                            return true
                        }
                        return false
                    },
                    onPanResponderGrant: (e, gestureState) => {
                        // console.log({e})
                        let pageY = e.nativeEvent.pageY
                        let topY = height - layoutRef.current.h1
                        if (pageY <= topY && !mask) {
                            e.stopPropagation()
                            hide()
                        }
                    }
                }).panHandlers}
            >
                <Animated.View
                    style={Object.assign({}, styles.wrapper, { transform: [{ translateY: animatedValue }] })}
                    // onLayout={e => {
                    //     let target: LayoutRectangle = e.nativeEvent.layout
                    //     layoutRef.current.h1 = target.height
                    // }}

                    ref={viewRef}
                >
                    {props.children}
                </Animated.View>
            </View>
        )
    })



const styles = StyleSheet.create({
    container: {
        position: 'absolute',
        left: 0,
        right: 0,
        top: 0,
        bottom: 0,
        zIndex: 999,
        // display: 'flex',
        flexDirection: 'column',
        backgroundColor: '#00000055',
        overflow: 'hidden',
    },
    wrapper: {
        position: 'absolute',
        display: 'flex',
        flexDirection: 'column',
        // backgroundColor: 'pink',
        width: '100%',
        top: '100%'
    },
    empty: {
        flex: 1, position: 'relative',
        //  backgroundColor: 'cyan'
    }
})




const useCallbackState = <T,>(od: T): [T, (d: T, callback?: Function) => void] => {
    const cbRef = React.useRef<Function>()
    const [data, setData] = React.useState<T>(od)
    React.useEffect(() => {
        cbRef.current && cbRef.current(data)
    }, [data])

    return [
        data,
        (d: T, callback?: Function) => {
            cbRef.current = callback;
            setData(d)
        }
    ]
}
